home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / challenge / 13.06 / ChallengeHexGame.sit / Challenge, Hex Game / Dynamic Memory4.c next >
Text File  |  1997-05-07  |  5KB  |  204 lines

  1. typedef struct Header
  2. {
  3.     long
  4.         size;    // the size in bytes of the block
  5.     
  6.     struct Header
  7.         *prev,    // the previous block's header
  8.         *next;    // the next block's header
  9. } Header;
  10.  
  11. void InitializeHeap(Header *heapStart, long size);
  12. void ChopBlock(Header *theBlock, long fragSize);
  13. void *AllocateBlock(long size);
  14. void FuseBlocks(Header *block);
  15. void FreeBlock(void *data);
  16. void HeapSummary(void);
  17. Boolean IsPointerValid(void *data);
  18. void SetHeap(Header *start);
  19. Header *GetHeap(void);
  20.  
  21. Header
  22.     *gHeapStart;
  23.  
  24. long
  25.     gFreeBlocks,
  26.     gUsedBlocks,
  27.     gFreeSpace,
  28.     gUsedSpace,
  29.     gTotalSpace;
  30.  
  31.  
  32. void InitializeHeap
  33. (
  34.     // these are assumed to be valid; no error-checking is performed
  35.     Header *heapStart,    // the address of the start of the heap zone
  36.     long    size        // the size of the zone
  37. )
  38. {
  39.     heapStart->size = size - sizeof (Header);    // mark the size of the zone
  40.     heapStart->prev = nil;                        // mark as being the first block…
  41.     heapStart->next = nil;                        // …and the last
  42.     gHeapStart = heapStart;                        // initialize the global heap start pointer
  43. }
  44.  
  45. void ChopBlock
  46. (
  47.     // these are assumed to be valid; fragSize must be less than theBlock->size
  48.     Header *theBlock,    // the block to chop
  49.     long fragSize        // the size of the first new fragment
  50. )
  51. {
  52.     Header
  53.         *newBlock;
  54.     
  55.     newBlock = (Header *) (((char *) theBlock) + sizeof (Header) + fragSize);
  56.     newBlock->size = theBlock->size - fragSize - sizeof (Header);    // the remaining space
  57.     newBlock->prev = theBlock;    // newBlock comes after theBlock
  58.     newBlock->next = theBlock->next;    // it gets inserted between theBlock and theBlock->next
  59.     if (theBlock->next)
  60.         theBlock->next->prev = newBlock;
  61.     theBlock->size = fragSize;    // theBlock gets just what was asked for
  62.     theBlock->next = newBlock;    // its new next block is newBlock
  63. }
  64.  
  65. void *AllocateBlock
  66. (
  67.     long    size        // the size of the desired block
  68. )
  69. {
  70.     const long
  71.         BLOCK_IN_USE_MASK = 0x80000000, // if this bit is set in the 'size' field,
  72.                                         // the block is in use
  73.         MIN_BLOCK_SIZE = 80;            // the smallest usable block (board data + pointers)
  74.     
  75.     Header
  76.         *currentBlock;    // a pointer to the block currently being considered
  77.     
  78.     currentBlock = gHeapStart;
  79.     
  80.     // loop until either there are no more blocks or a fitting one is found
  81.     while (currentBlock && ((currentBlock->size & BLOCK_IN_USE_MASK) || (currentBlock->size < size)))
  82.         currentBlock = currentBlock->next;
  83.     
  84.     if (currentBlock)    // a valid block was found
  85.     {
  86.         // if the block is much bigger than needed
  87.         if ((currentBlock->size - size) > (MIN_BLOCK_SIZE + sizeof (Header)))
  88.             ChopBlock(currentBlock, size);    // cut off a piece of exactly the right size
  89.         currentBlock->size |= BLOCK_IN_USE_MASK;    // mark as being in use
  90.         
  91.         // return a pointer to just after the block header
  92.         return (char *) (currentBlock + 1);
  93.     }
  94.     else
  95.         // indicate that allocation failed
  96.         return nil;
  97. }
  98.  
  99. void FuseBlocks
  100. (
  101.     Header *block    // the block to fuse with its following neighbor
  102. )
  103. {
  104.     Header
  105.         *neighbor;
  106.     
  107.     neighbor = block->next;
  108.     block->next = neighbor->next;
  109.     neighbor->next->prev = block;
  110.     block->size += sizeof (Header) + neighbor->size;    // blocks must not be in use
  111. }
  112.  
  113. void FreeBlock
  114. (
  115.     void
  116.         *data    // the block of data to free, fusing with its neighbors if possible
  117. )
  118. {    
  119.     const long
  120.         BLOCK_IN_USE_MASK = 0x80000000;    // bit in size field used to indicate use of blocks
  121.     
  122.     Header
  123.         *theBlock;        // the data block's header
  124.     
  125.     // the header is located just before the data
  126.     theBlock = ((Header *) data) - 1;
  127.     
  128.     // assumed to be in use, with flag set; here it is reset
  129.     if (theBlock->size & BLOCK_IN_USE_MASK)
  130.         theBlock->size -= BLOCK_IN_USE_MASK;
  131.     
  132.     // if there is a next block and it is free
  133.     if (theBlock->next && !(theBlock->next->size & BLOCK_IN_USE_MASK))
  134.         FuseBlocks(theBlock);
  135.     
  136.     // if there is a previous block and it is free
  137.     if (theBlock->prev && !(theBlock->prev->size & BLOCK_IN_USE_MASK))
  138.         FuseBlocks(theBlock->prev);
  139.     
  140. }
  141.  
  142. void HeapSummary
  143. (
  144.     void
  145. )
  146. {
  147.     const long
  148.         IN_USE_MASK = 0x80000000;
  149.     
  150.     Header
  151.         *block;
  152.     
  153.     block = gHeapStart;
  154.     while (block->next)
  155.         block = block->next;
  156.     
  157.     gFreeBlocks = gUsedBlocks = gFreeSpace = gUsedSpace = 0;
  158.     
  159.     while (block)
  160.     {
  161.         if (block->size & IN_USE_MASK)
  162.         {
  163.             gUsedBlocks++;
  164.             gUsedSpace += block->size - IN_USE_MASK;
  165.         }
  166.         else
  167.         {
  168.             gFreeBlocks++;
  169.             gFreeSpace += block->size;
  170.         }
  171.         block = block->prev;
  172.     }
  173.     gTotalSpace = (gFreeBlocks + gUsedBlocks) * sizeof (Header) + gFreeSpace + gUsedSpace;
  174. }
  175.  
  176. Boolean IsPointerValid(void *data)
  177. {
  178.     Header
  179.         *theBlock,
  180.         *compBlock;
  181.     
  182.     theBlock = ((Header *) data) - 1;
  183.     compBlock = gHeapStart;
  184.     
  185.     while(compBlock && compBlock != theBlock)
  186.         compBlock = compBlock->next;
  187.     
  188.     if (compBlock == theBlock)
  189.         return true;
  190.     else
  191.         return false;
  192.         
  193. }
  194.  
  195. void SetHeap(Header *start)
  196. {
  197.     gHeapStart = start;
  198. }
  199.  
  200. Header *GetHeap(void)
  201. {
  202.     return gHeapStart;
  203. }
  204.